PLATFORM
  • Tails

    Create websites with TailwindCSS

  • Blocks

    Design blocks for your website

  • Wave

    Start building the next great SAAS

  • Pines

    Alpine & Tailwind UI Library

  • Auth

    Plug'n Play Authentication for Laravel

  • Designer comingsoon

    Create website designs with AI

  • DevBlog comingsoon

    Blog platform for developers

  • Static

    Build a simple static website

  • SaaS Adventure

    21-day program to build a SAAS

Question By
Solved

How to add Codepen in Markdown X ?

Solved
ansariabushama

Dec 29th, 2021 12:46 AM

anyone know how to add markdown x editor codepen Screenshot from 2021-12-29 14-11-49.png i don't understand doc if there is video or any https://devdojo.com/markdownx/docs/concepts/liquid-tags

PostsEditor.php

<?php

namespace App\Http\Livewire\Dashboard;

use App\Models\Post;
use Livewire\Component;
use Livewire\WithFileUploads;
use Illuminate\Support\Str;

use Validator;

class PostsEditor extends Component
{
    use WithFileUploads;
    public $post;
    public $image;

    protected $listeners = [
        'markdown-x:update' => 'updateBody',
    ];

    protected $rules = [
        'post.title' => 'required|min:6',
        'post.body' => 'required|min:6',
        'post.image' => '',
        'post.slug' => '',
        'post.status' => '',
        'post.excerpt' => '',
        'post.type' => '',
        'post.featured' => '',
        'post.meta_title' => '',
        'post.meta_description' => '',
        'post.meta_schema' => '',
        'post.meta_data' => '',
        'image' => 'nullable|image|max:5120',
    ];

    public function mount(Post $post)
    {
        if (isset($post)) {
            $this->post = $post;
        } else {
            $this->post = new Post;
        }
    }

    public function savePost()
    {
        $validator = Validator::make($this->getDataForValidation($this->rules), $this->rules);

        if ($validator->fails()) {
            $this->dispatchBrowserEvent('notification-show', [
                'type' => 'error',
                'message' => str_replace('post.', '', $validator->errors()->first())
            ]);
            return;
        }

        $this->validate();

        $this->post->user_id = auth()->user()->id;
        if (!isset($this->post->id)) {
            $this->post->slug = Str::slug($this->post->title);
        }

        if ($this->image) {
            $this->post->image = $this->image->store('images');
            $this->image = null;
        }

        foreach ($this->post->toArray() as $column => $value) {
            if (is_null($value) && $column != 'image') {
                unset($this->post->{$column});
            }
        }

        $this->post->save();
        $this->dispatchBrowserEvent('set-url', [
            'url' => '/dashboard/posts/edit/' . $this->post->id,
        ]);
        $this->dispatchBrowserEvent('notification-show', [
            'type' => 'success',
            'message' => 'Successfully saved post.'
        ]);
    }

    public function updateBody($value)
    {
        $this->post->body = $value;
    }

    public function delete(){
        $this->post->delete();
        session()->flash('notification',
            [
                'type' => 'success',
                'message' => 'Successfully Deleted Post'
            ]);
        return redirect('/dashboard');
    }

    public function removeTemporaryImage()
    {

        $this->image = null;
    }

    public function removeImage()
    {
        $this->post->image = null;
    }

    public function render()
    {
        return view('livewire.dashboard.posts-editor')->extends('dashboard.layout');
    }
}

how to insert codepen code plz comment below

bobbyiliev

Dec 29th, 2021 01:49 AM

Hi there,

You can implement Liquid tags by following the steps here:

MarkdownX Liquid Tags

We recently had a similar discussion here where I've shared the steps on how to implement that:

Discussion

Let me know how it goes.

Regards,

Bobby

ansariabushama

Dec 29th, 2021 02:51 AM

now i got this 404 Screenshot from 2021-12-29 16-19-11.png

MarkdownX.php my code

<?php

namespace App\Http\Livewire;

use Livewire\Component;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Storage;
use GrahamCampbell\Markdown\Facades\Markdown as MarkdownConverter;

class MarkdownX extends Component
{

    public $content;
    public $contentPreview;
    public $name;
    public $key;
    public $style;
    public $section = 'write';

    /**
     * Laravel livewire listeners, learn more at https://laravel-livewire.com/docs/events#event-listeners
     *
     * 'markdown-x-image-upload' => uploads image files from the editor
     */
    protected $listeners = [
        'markdown-x-image-upload' => 'upload',
        'markdown-x-giphy-load' => 'getGiphyTrendingImages',
        'markdown-x-giphy-search' => 'getGiphySearchImages'
    ];

    /**
     * Mount the MarkdownX component, you can pass the current content, the name for the textarea field,
     * and a generic Key. This key can be specified so that way you can include multiple MarkdownX
     * editors in a single page.
     *
     * @param string $content
     * @param string $name
     * @param string $key
     * @return void
     */
    public function mount($content = '', $name = '', $key = '')
    {
        $this->content = $content;
        $this->name = $name;
        $this->key = $key;
        $this->updateContentPreview();
    }

    /**
     * Anytime the editor is blurred, this function will be triggered and it will updated the $content,
     * this will also emit an event to the parent component with the updated content.
     *
     * @param array $data
     */
    public function update($data)
    {
        $content = $data['content'];
        $this->content = $content;
        $this->emitUp('markdown-x:update', $this->content);
    }

    /**
     * When the content changes this function will fire an event with the updatedPmark
     * content is being emitted to the parent component.
     *
     */
    public function updatedContent()
    {
        $this->emitUp('markdown-x:update', $this->content);
    }

    /**
     * This function will update the Content Preview when user clicks on the Preview tab in the
     * Markdown editor toolbar.
     *
     * Note: This function can be overwritten with your customer Markdown parser. This is the
     * only function that will/can be changed when you upgrade to the latest version of the
     * MarkdownX editor.
     *
     */
    // public function updateContentPreview(){
    //     $this->contentPreview = Str::markdown($this->content);
    // }

    public function updateContentPreview()
    {

        $this->contentPreview = $this->parseLiquidTags(Str::markdown($this->content));
    }

    public static function parseLiquidTags($html)
    {
        $matches = "";

        // If we find at least one liquid tag
        if (preg_match_all('/{% .* %}/', $html, $matches) && isset($matches[0])) {

            // loop through each of the liquid tags
            foreach ($matches[0] as $index => $match) {

                // replace multiple spaces with single space
                $matchArray = explode(" ", preg_replace('!\s+!', ' ', $match));

                // gaurantee we have the first value and run specific function for specific tag
                if ($matchArray[1]) {
                    switch ($matchArray[1]) {
                        case 'youtube':
                            $html = self::replaceYouTubeTag($html, $matchArray, $match);
                            break;
                        case 'codepen':
                            $html = self::replaceCodePenTag($html, $matchArray, $match);
                            break;
                        case 'codesandbox':
                            $html = self::replaceCodeSandboxTag($html, $matchArray, $match);
                            break;
                        case 'buymeacoffee':
                            $html = self::replaceBuyMeACoffeeTag($html, $matchArray, $match);
                            break;
                        case 'giphy':
                            $html = self::replaceGiphyTag($html, $matchArray, $match);
                            break;
                    }
                }
            }
        }

        return $html;
    }

    public static function replaceCodePenTag($html, $tagArray, $original_string)
    {
        if (isset($tagArray[2])) {
            $codepenEmbedURL = str_replace("/pen/", "/embed/", $tagArray[2]);
            $defaultTag = 'default-tab=result';
            if (isset($tagArray[3]) && $tagArray[3] != '%}') {
                $defaultTag = $tagArray[3];
            }
            $codepenEmbed = '<div class="overflow-hidden border border-gray-100 rounded-lg"><iframe loading="lazy" height="600" style="width: 100%;" scrolling="no" src="' . $codepenEmbedURL . '?height=600&theme-id=24057&' . $defaultTag . '" frameborder="no" allowtransparency="true" allowfullscreen="true"></iframe></div>';
            $html = str_replace($original_string, $codepenEmbed, $html);
        }
        return $html;
    }



    /**
     * This function is called from the markdown-x view when the image file input has changed
     * The following data is sent with the payload:
     * {
     *      image: reader.result,
     *      name: file.name,
     *      key: key,
     *      text: "![" + file.name + "](Uploading...)"
     * }
     *
     * @param array $payload
     * @return void
     */
    public function upload($payload)
    {

        $payload = (object)$payload;

        $path = 'images/' . strtolower(date('FY')) . '/';
        $fullPath = '';

        try {

            $original_filename = pathinfo($payload->name, PATHINFO_FILENAME);
            $filename = $original_filename;
            $extension = explode('/', mime_content_type($payload->image))[1];
            $filename_counter = 1;

            // Make sure the filename does not exist, if it does make sure to add a number to the end 1, 2, 3, etc...
            while (Storage::disk(config('markdownx.storage.disk'))->exists($path . $filename . '.' . $extension)) {
                $filename = Str::slug($original_filename) . (string) ($filename_counter++);
            }

            $fullPath = $path . $filename . '.' . $extension;

            // Get the Base64 string to store
            @list($type, $file_data) = explode(';', $payload->image);
            @list(, $file_data) = explode(',', $file_data);
            $type = explode('/', $type)[1];

            if (!in_array($type, config('markdownx.image.allowed_file_types'))) {
                $this->dispatchBrowserEvent('markdown-x-image-uploaded', [
                    'status' => 400,
                    'message' => 'File type not supported. Must be of type ' . implode(', ', config('markdownx.image.allowed_file_types')),
                    'key' => $payload->key,
                    'text' => $payload->text
                ]);
                return;
            }

            Storage::disk(config('markdownx.storage.disk'))->put($fullPath, base64_decode($file_data), 'public');

            $this->dispatchBrowserEvent('markdown-x-image-uploaded', [
                'status' => 200,
                'message' => 'Successfully uploaded image.',
                'path' => str_replace(' ', '%20', Storage::url($fullPath)),
                'key' => $payload->key,
                'text' => $payload->text,
                'name' => $payload->name
            ]);
        } catch (Exception $e) {
            $this->dispatchBrowserEvent('markdown-x-image-uploaded', [
                'status' => 400,
                'message' => 'Error when trying to upload.',
                'key' => $payload->key,
                'text' => $payload->text
            ]);
        }
    }

    public function getGiphyImages($payload)
    {
        $api_key = config('markdownx.integrations.giphy.api_key');

        $response = Http::get('https://api.giphy.com/v1/gifs/trending', [
            'api_key' => $api_key,
            'limit' => 30,
            'rating' => 'pg'
        ]);

        if ($response->ok()) {
            $this->sendResultsToView($response);
        }
    }

    public function getGiphyTrendingImages($payload)
    {
        $api_key = config('markdownx.integrations.giphy.api_key');

        $response = Http::get('https://api.giphy.com/v1/gifs/trending', [
            'api_key' => $api_key,
            'limit' => 30,
            'rating' => 'pg'
        ]);

        if ($response->ok()) {
            $this->sendResultsToView($response, $payload['key']);
        }
    }

    public function getGiphySearchImages($payload)
    {
        $api_key = config('markdownx.integrations.giphy.api_key');

        $response = Http::get('api.giphy.com/v1/gifs/search', [
            'api_key' => $api_key,
            'q' => $payload['search'],
            'limit' => 30,
            'rating' => 'pg'
        ]);


        if ($response->ok()) {
            $this->sendResultsToView($response, $payload['key']);
        }
    }

    public function sendResultsToView($response, $key)
    {
        $parse_giphy_results = [];
        foreach ($response->json()['data'] as $result) {
            array_push(
                $parse_giphy_results,
                [
                    'image' => $result['images']['fixed_height_small']['url'],
                    'embed' => $result['embed_url']
                ]
            );
        }

        $this->dispatchBrowserEvent('markdown-x-giphy-results', [
            'status' => 200,
            'message' => 'Successfully returned results.',
            'results' => $parse_giphy_results,
            'key' => $key,
        ]);
    }

    /**
     * Render the markdown-x view. Hazah!
     *
     */
    public function render()
    {
        return view('livewire.markdown-x');
    }
}

bobbyiliev

Dec 29th, 2021 03:07 AM

Hi there,

I was able to replicate the problem. The bellow method should work as expected:

public static function replaceCodePenTag($html, $tagArray, $original_string){
    if(isset($tagArray[2]) && isset($tagArray[3])){
        $codepenEmbedLink = $tagArray[2] . ' ' .$tagArray[3];
        preg_match_all('/<a[^>]+href=([\'"])(?<href>.+?)\1[^>]*>/i', $codepenEmbedLink, $result);
        if (empty($result['href'])) {
            return $html;
        }
        $codepenEmbed = $result['href'][0];

        $codepenEmbedURL = str_replace("/pen/", "/embed/", $codepenEmbed);
        $defaultTag = 'default-tab=result';
        if(isset($tagArray[4]) && $tagArray[4] != '%}'){
            $defaultTag = $tagArray[4];
        }
        $codepenEmbed = '<div class="overflow-hidden border border-gray-100 rounded-lg"><iframe loading="lazy" height="600" style="width: 100%;" scrolling="no" src="' . $codepenEmbedURL . '?height=600&theme-id=24057&' . $defaultTag . '" frameborder="no" allowtransparency="true" allowfullscreen="true"></iframe></div>';
        $html = str_replace($original_string, $codepenEmbed, $html);
    }
    return $html;
}

Let me know how it goes.

Best,

Bobby

ansariabushama

Dec 29th, 2021 03:26 AM

it working only backend Screenshot from 2021-12-29 16-54-16.png but not show in frontend Screenshot from 2021-12-29 16-55-14.png

Blade file

@extends('layouts.app')

@section('content')

@if($post->type == App\Models\Post::TYPE_POST)
<div class="absolute top-0 left-0 hidden w-full h-auto mt-32 bg-center bg-cover lg:block lg:h-96"
    style="background-image:url('{{ Storage::url($post->image) }}')">
    <div class="absolute w-full h-full bg-gradient-to-b from-transparent to-white"></div>
    <div class="absolute w-full h-full bg-white opacity-80"></div>
</div>

<div class="box-content relative max-w-6xl mx-auto overflow-hidden lg:pt-12 lg:px-10 lg:rounded-md h-96">
    <img src="{{ Storage::url($post->image) }}" class="object-cover w-full h-96 lg:rounded-md" />
</div>
@endif

<article class="px-6 py-20 mx-auto prose xl:prose-xl 2xl:prose-2xl lg:px-0">
    <h1>{{ $post->title }}</h1>
    {!! Str::markdown($post->body) !!}
</article>
@endsection
bobbyiliev

Dec 29th, 2021 03:30 AM

Hello,

In order for this to work, you would need to include the liquid tags method in your frontend controller too.

Basically, when passing the post body to the front end, you need to run it through the liquid tags method.

Best,

Bobby

ansariabushama

Dec 29th, 2021 03:36 AM

how to in controller add ?

BlogController.php

<?php

namespace App\Http\Controllers;

use App\Models\Post;
use Illuminate\Http\Request;

class BlogController extends Controller
{
    public function home()
    {
        $featured = Post::where('featured', 1)->where('type', 'post')->first();
        return view('home', compact('featured'));
    }

    public function post(Post $post)
    {
        return view('post', compact('post'));
    }
    
}

bobbyiliev

Dec 29th, 2021 03:50 AM

Hi there,

It will work the same way as with the MarkdownX method. Just add the liquid tags method to that controller and then before passing the post to the view do:

        $featured = Post::where('featured', 1)->where('type', 'post')->first();
        $featured->body = $this->parseLiquidTags(Str::markdown($featured->body));
        return view('home', compact('featured'));

Then in your Blade view, you can remove the Str::markdown method and just display the content.

Best,

Bobby

ansariabushama

Dec 29th, 2021 04:00 AM

Done Thanks

one more question. is this impact my page performance ?

bobbyiliev

Dec 29th, 2021 04:05 AM

Best Answer

Hello,

There should not be any performance impact as this is just a pure PHP function so there are no fancy external calls and it is just a single call to the database.

Of course as you are including external resources like codepen, this will make it so that your website loads more resources, but it is not related with the simple liquid tag parsing.